#include <stdio.h>
#include <string.h>
#ifndef _MSC_VER
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#define closesocket close
#else
#define sleep(sec) Sleep(sec * 1000)
typedef int socklen_t;
#endif   // !_MSC_VER
#include <openssl/ssl.h>
#include <openssl/err.h>

#define PORT 18888
#define BUFFER_SIZE 1024

SSL_CTX *create_ssl_context() {
    SSL_CTX *ctx = NULL;

    // 使用 TLS 服务器方法（兼容 OpenSSL 3.x）
#if OPENSSL_VERSION_NUMBER < 0x1010000fL
    ctx = SSL_CTX_new(SSLv23_server_method());
#else
    ctx = SSL_CTX_new(TLS_server_method());
#endif
    if (!ctx) {
        ERR_print_errors_fp(stderr);
        return NULL;
    }

    // 强制使用 TLS 1.2
#if OPENSSL_VERSION_NUMBER < 0x1010000fL
    SSL_CTX_set_options(ctx,                   SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1);
#else
    SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION);
    SSL_CTX_set_max_proto_version(ctx, TLS1_2_VERSION);
#endif

    // 加载证书和私钥
    if (SSL_CTX_use_certificate_file(ctx, "cert.pem", SSL_FILETYPE_PEM) <= 0) {
        ERR_print_errors_fp(stderr);
        SSL_CTX_free(ctx);
        return NULL;
    }
    if (SSL_CTX_use_PrivateKey_file(ctx, "key.pem", SSL_FILETYPE_PEM) <= 0) {
        ERR_print_errors_fp(stderr);
        SSL_CTX_free(ctx);
        return NULL;
    }

    return ctx;
}

int main() {
#ifdef _MSC_VER
    WSADATA data;
    WORD    version = MAKEWORD(2, 2);

    WSAStartup(version, &data);
#endif
    SSL_CTX *ctx;
    SSL *ssl;
    int server_fd, client_fd;
    struct sockaddr_in server_addr, client_addr;
    socklen_t client_len = sizeof(client_addr);
    char buffer[BUFFER_SIZE];

    // 初始化 OpenSSL 3.x
#if OPENSSL_VERSION_NUMBER < 0x1010000fL
    (void)SSL_library_init();
    SSL_load_error_strings();
#else
    OPENSSL_init_ssl(0, NULL);
#endif

    ctx = create_ssl_context();
    if (!ctx) exit(EXIT_FAILURE);

    // 创建 TCP 套接字
    server_fd = socket(AF_INET, SOCK_STREAM, 0);
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = INADDR_ANY;
    server_addr.sin_port = htons(PORT);

    if (bind(server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0)
    {
        printf("bind port %d failed.\n", PORT);
        return -1;
    };
    if (listen(server_fd, 5) < 0)
    {
        printf("listen port %d failed.\n", PORT);
        return -1;
    };

    printf("Server listening on port %d...\n", PORT);

    client_fd = accept(server_fd, (struct sockaddr*)&client_addr, &client_len);
    printf("Client connected\n");

    ssl = SSL_new(ctx);
    SSL_set_fd(ssl, client_fd);

    if (SSL_accept(ssl) <= 0) {
        ERR_print_errors_fp(stderr);
    } else {
        int bytes = SSL_read(ssl, buffer, sizeof(buffer));
        buffer[bytes] = '\0';
        printf("Received: %s\n", buffer);

        //sleep(3);

        SSL_write(ssl, "Hello from TLS Server!", strlen("Hello from TLS Server!"));
    }

    SSL_shutdown(ssl);
    SSL_free(ssl);
    closesocket(client_fd);
    SSL_CTX_free(ctx);
    closesocket(server_fd);

    return 0;
}
